package httpd

import (
	"encoding/json"
	"fmt"
	"github.com/hashicorp/raft"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"raftkv/pkg/store"
	"strings"
)

type Store interface {
	Get(Key string,level store.ConsistencyLevel)(string,error)
	Set(key,value string)error
	Delete(key string)error
	Join(nodeID ,httpAddr ,addr string) error
	LeaderAPIAddr() string
	SetMeta(key,value string) error
}
type Service struct{
	ln net.Listener
	store Store
	addr string
	logger *log.Logger
}

func (s *Service) FormRedirect(r *http.Request,host string)string{
	protocol := "http"
	rq := r.URL.RawQuery
	if rq != ""{
		rq = fmt.Sprintf("?%s",rq)
	}
	return fmt.Sprintf("%s://%s%s%s",protocol,host,r.URL.Path,rq)
}
func NewHttpService(addr string,store Store) *Service{
	return &Service{
		addr : addr,
		store: store,
		logger: log.New(os.Stderr,"[httpd] ",log.LstdFlags),
	}
}
// ServeHTTP 请求分派
func (s *Service) ServeHTTP(w http.ResponseWriter,r *http.Request){
	if strings.HasPrefix(r.URL.Path,"/key"){
		s.logger.Println("method:",r.Method)
		s.handleKeyRequest(w,r)
	}else if r.URL.Path == "/join" {
		s.handleJoin(w,r)
	}else{
		w.WriteHeader(http.StatusNotFound)
	}

}
func (s *Service)Close(){
	err := s.ln.Close()
	if err != nil {
		return
	}
}
func (s *Service) Start() error {
	server := http.Server{
		Handler: s,
	}
	ln,err := net.Listen("tcp",s.addr)
	if err != nil{
		return err
	}
	s.ln =ln
	http.Handle("/",s)
	go func() {
		err:=server.Serve(s.ln)
		if err!=nil{
			s.logger.Fatalf("Http serve :%s",err)
		}
	}()
	return nil
}
// handleJoin 处理集群节点加入
func (s *Service) handleJoin(w http.ResponseWriter, r *http.Request) {
	m := map[string]string{}
	if err := json.NewDecoder(r.Body).Decode(&m);err !=nil{
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	if len(m)!=3{
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	httpAddr,ok := m["httpAddr"]
	if !ok{
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	raftAddr,ok:=m["raftAddr"]
	if !ok{
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	nodeID, ok := m["id"]
	if !ok {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	if err:=s.store.Join(nodeID,httpAddr,raftAddr);err != nil{
		if err == raft.ErrNotLeader{
			leader := s.store.LeaderAPIAddr()
			if leader==""{
				http.Error(w,err.Error(),http.StatusServiceUnavailable)
				return
			}
			redirect := s.FormRedirect(r,leader)
			http.Redirect(w,r,redirect,http.StatusTemporaryRedirect)//307?
			return
		}
	}
	w.WriteHeader(http.StatusInternalServerError)
	return
}
// handleKeyRequest RestFul接口，处理kv增删改查
func (s *Service) handleKeyRequest(w http.ResponseWriter, r *http.Request) {
	getKey := func()string{
		parts := strings.Split(r.URL.Path,"/")
		if len(parts)!=3{
			w.WriteHeader(http.StatusBadRequest)
			return ""
		}
		return parts[2]
	}
	switch r.Method {
	case "GET":
		k := getKey()
		if k == "" {
			w.WriteHeader(http.StatusBadRequest)
			return
		}
		lvl, err := level(r)
		if err != nil {
			w.WriteHeader(http.StatusBadRequest)
			return
		}
		value, err := s.store.Get(k, lvl)
		if err != nil {
			if err == raft.ErrNotLeader {
				leader := s.store.LeaderAPIAddr() //TODO:
				if leader == "" {
					http.Error(w, err.Error(), http.StatusServiceUnavailable)
					return
				}
				redirect := s.FormRedirect(r, leader)
				http.Redirect(w, r, redirect, http.StatusTemporaryRedirect)
				return
			}
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		data, err := json.Marshal(map[string]string{k: value})
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		if _, err := io.WriteString(w, string(data)); err != nil {
			s.logger.Printf("fail to WriteString:%v\n", err)
		}
	case "POST":
		paramMap := map[string]string{}
		if err := json.NewDecoder(r.Body).Decode(&paramMap); err != nil {

			w.WriteHeader(http.StatusBadRequest)
			return
		}
		for k, v := range paramMap {
			if err := s.store.Set(k, v); err != nil {
				if err == raft.ErrNotLeader {

					leader := s.store.LeaderAPIAddr()
					if leader == "" {
						http.Error(w, err.Error(), http.StatusServiceUnavailable)
						return
					}
					redirect := s.FormRedirect(r, leader)
					http.Redirect(w, r, redirect, http.StatusTemporaryRedirect)
					return
				}
				w.WriteHeader(http.StatusInternalServerError)
				return
			}
		}
	case "DELETE":
		k := getKey()
		if k == "" {
			w.WriteHeader(http.StatusBadRequest)
			return
		}
		if err := s.store.Delete(k); err != nil {
			if err == raft.ErrNotLeader {
				leader := s.store.LeaderAPIAddr()
				if leader == "" {
					http.Error(w, err.Error(), http.StatusServiceUnavailable)
					return
				}
				redirect := s.FormRedirect(r, leader)
				http.Redirect(w, r, redirect, http.StatusTemporaryRedirect)
				return
			}
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		s.store.Delete(k)
	default:
		w.WriteHeader(http.StatusMethodNotAllowed)
	}
}
// level 获取节点读取模式
func level(req *http.Request)(store.ConsistencyLevel,error){
	query := req.URL.Query()
	lvl := strings.TrimSpace(query.Get("level"))
	switch strings.ToLower(lvl) {
	case "default":
		return store.Default,nil
	case "stale":
		return store.Stale,nil
	case "consistent":
		return store.Consistent,nil
	default:
		return store.Default,nil
	}
}
// Addr 获取监听的地址
func (s *Service) Addr() net.Addr {
	return s.ln.Addr()
}